/*
Copyright (C) 2013 Matthew Netsch

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#define _CRT_SECURE_NO_WARNINGS
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QFileDialog>
#include <QMessageBox>
#include <QFileInfo>
#include <QDir>
#include <QInputDialog>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    toolbar(NULL),
    passview(NULL),
    passmodel(NULL),
    saved_passmodel(NULL),
    ui(new Ui::MainWindow),
    dbMan(NULL),
    is_untitled(true),
    is_unsaved(false),
    doc_name(NULL),
    doc_key(NULL)
{
    ui->setupUi(this);

    //Create database manager
    dbMan = PassMan::IDatabaseManager::Create(PassMan::IDatabaseManager::DATABASE_FILE);

    //Toolbar
    toolbar = new PassTool();
    addToolBar(toolbar);

    //Signals
    connect(toolbar, SIGNAL(newDoc()), this, SLOT(newDoc()));
    connect(toolbar, SIGNAL(saveDoc()), this, SLOT(saveDoc()));
    connect(toolbar, SIGNAL(openDoc()), this, SLOT(openDoc()));
    connect(toolbar, SIGNAL(deleteDoc()), this, SLOT(deleteDoc()));

    //Setup state
    newDoc();
}

MainWindow::~MainWindow()
{
    destroyDoc();
    delete ui;
    delete toolbar;
    delete dbMan;

    free(doc_name);
    free(doc_key);
}

void
MainWindow::deleteDoc()
{
    if (is_untitled || !saved_passmodel)
    {
        return;
    }

    //Check to make sure user wants to delete
    QMessageBox msgBox;
    msgBox.setText("Are you sure you want to permanently delete this file?");
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
    msgBox.setDefaultButton(QMessageBox::Yes);
    msgBox.setWindowIcon(QIcon(":/icons/passman.ico"));
    msgBox.setIcon(QMessageBox::Question);

    if (msgBox.exec() == QMessageBox::Cancel)
    {
        return;
    }

    //Delete permanently
    dbMan->Destroy(saved_passmodel);

    //Create new document
    is_unsaved = false;
    newDoc();
}

void
MainWindow::openDoc()
{
    //Make sure save changes first
    if (!checkSave())
    {
        return;
    }

    QString path;

    if (doc_name)
    {
        path = QFileInfo(QString::fromLatin1(doc_name)).absolutePath();
    }
    else
    {
        path = QDir::currentPath();
    }

    //Get name and key of file to open
    QString name = QFileDialog::getOpenFileName(this,
                                                "Open File",
                                                path);


    if (name.isEmpty() || name.isNull())
    {
        return;
    }

    bool ok;
    QString key = QInputDialog::getText(this,
                                        "Enter File Key",
                                        "Key:",
                                        QLineEdit::Password,
                                        QString(),
                                        &ok,
                                        0,
                                        Qt::ImhSensitiveData);

    if (!ok || key.isEmpty() || key.isNull())
    {
        return;
    }

    //Open doc with name and key
    createDoc((char*)name.toLatin1().constData(), (char*)key.toLatin1().constData(), false);
}

void
MainWindow::createDoc(
        char *name,
        char *key,
        bool  untitled)
{
    PassMan::IDatabase *db;

    //PassModel
    if (untitled)
    {
        db = dbMan->Create(NULL, NULL), toolbar->getShowPass();
    }
    else
    {
        db = dbMan->Retrieve(name, key), toolbar->getShowPass();
    }

    if (!db)
    {
        //Error
        QMessageBox::critical(this, "Error", "Could not open file or bad pass.");
        return;
    }

    //Destroy old doc
    destroyDoc();

    is_untitled = untitled;
    is_unsaved  = false;

    //Set the new name and key of this doc
    setName(name);
    setKey(key);

    //Create the PassModel of the database
    passmodel = new PassModel(db, toolbar->getShowPass());
    saved_passmodel = passmodel->clone();

    //PassView
    passview = new PassView(passmodel, centralWidget()->layout());
    passview->show();

    //Connect signals
    connect(toolbar, SIGNAL(passAdded(QString, QString)), passmodel, SLOT(addPass(QString, QString)));
    connect(toolbar, SIGNAL(passDeleted()), passview, SLOT(deleteSelected()));
    connect(passview, SIGNAL(rowDeleted(int)), passmodel, SLOT(deleteRow(int)));
    connect(toolbar, SIGNAL(passChanged(char*)), passview, SLOT(changeSelectedPass(char*)));
    connect(passview, SIGNAL(passChanged(int,char*)), passmodel, SLOT(changePass(int,char*)));
    connect(toolbar, SIGNAL(passCopied()), passview, SLOT(copyPass()));
    connect(passview, SIGNAL(passCopied(int)), passmodel, SLOT(copyPass(int)));
    connect(toolbar, SIGNAL(passShowed(bool)), passmodel, SLOT(setShowPass(bool)));
    connect(passmodel, SIGNAL(modelChanged()), this, SLOT(notify()));
}

void
MainWindow::destroyDoc()
{
    if (saved_passmodel)
    {
        delete saved_passmodel;
        saved_passmodel = NULL;
    }

    //Destroy old doc if exist
    if (passview)
    {
        passview->disconnect();

        if (toolbar)
        {
            toolbar->disconnect(passview);
        }

        delete passview;
        passview = NULL;
    }

    if (passmodel)
    {
        passmodel->disconnect();

        if (toolbar)
        {
            toolbar->disconnect(passmodel);
        }

        delete passmodel;
        passmodel = NULL;
    }

    is_untitled = true;
    is_unsaved  = false;
}

//Return false if cancelled
bool
MainWindow::saveDoc()
{
    PassMan::IDatabase *db = (passmodel) ? passmodel->clone() : NULL;

    if (!db)
    {
        return false;
    }

    QString path;

    if (doc_name)
    {
        path = QFileInfo(QString::fromLatin1(doc_name)).absoluteFilePath();
    }
    else
    {
        path = QDir::currentPath();
    }

    QString name = QFileDialog::getSaveFileName(this,
                                                "Save File",
                                                path);


    if (name.isEmpty() || name.isNull())
    {
        return false;
    }

    //Check if key is NULL
    if (!doc_key)
    {
        bool ok;
        QString key = QInputDialog::getText(this,
                                            "Set File Key",
                                            "Key:",
                                            QLineEdit::Password,
                                            QString(),
                                            &ok,
                                            0,
                                            Qt::ImhSensitiveData);

        if (!ok || key.isEmpty() || key.isNull())
        {
            return false;
        }

        setKey((char*)key.toLatin1().constData());
    }

    is_unsaved  = false;
    is_untitled = false;
    setName((char*)name.toLatin1().constData());

    //Save doc
    db->setName(doc_name);
    db->setKey(doc_key);
    dbMan->Update(db);

    //Set last saved model to newly saved model
    if (saved_passmodel)
    {
        delete saved_passmodel;
    }

    saved_passmodel = db;
    return true;
}

//Return false if cancelled
bool
MainWindow::checkSave()
{
    if (!is_unsaved)
    {
        return true;
    }

    QMessageBox msgBox;
    msgBox.setText("Do you wish to save your changes?");
    msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
    msgBox.setDefaultButton(QMessageBox::Save);
    msgBox.setWindowIcon(QIcon(":/icons/passman.ico"));
    msgBox.setIcon(QMessageBox::Question);

    int result = msgBox.exec();

    switch (result)
    {
        case QMessageBox::Save:
            return saveDoc();

        case QMessageBox::Discard:
            return true;

        case QMessageBox::Cancel:
            return false;

        default:
            break;
    }

    return true;
}

void
MainWindow::newDoc()
{
    //Ignore command if was cancelled
    if (!checkSave())
    {
        return;
    }

    //Create new doc
    createDoc("Untitled", NULL, true);
}

void
MainWindow::notify()
{
    is_unsaved = (!(passmodel->isEqual(saved_passmodel)));
    setName(doc_name);
}

void
MainWindow::setName(
        char *name)
{
    if (!name)
    {
        return;
    }

    if (name != doc_name)
    {
        doc_name = (char*)realloc(doc_name, sizeof(char) * (strlen(name) + 1));

        if (!doc_name)
        {
            return;
        }
         
        strcpy(doc_name, name);
    }

    QString file_name = QFileInfo(QString::fromLatin1(doc_name)).fileName();

    char window_title[] = " - PassMan";
    char *combined_name = (char*)malloc(sizeof(char) * (file_name.length() + 2 + strlen(window_title)));

    if (!combined_name)
    {
        return;
    }

    strcpy(combined_name, file_name.toLatin1().constData());

    if (is_unsaved)
    {
        strcat(combined_name, "*");
    }

    strcat(combined_name, window_title);

    setWindowTitle(QString::fromLatin1(combined_name));

    free(combined_name);
}

void
MainWindow::setKey(
        char *key)
{
    //Free old key
    free(doc_key);
    doc_key = NULL;

    if (!key)
    {
        return;
    }

    //Create new key
    doc_key = (char*)malloc(sizeof(char) * (strlen(key) + 1));

    strcpy(doc_key, key);
}
